/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package structures.table;

import static common.Constants.EMPTY;
import common.Item;
import structures.grammar.ItemList;
import structures.grammar.Rule;
import structures.table.symboltable.ItemInfo;

/**
 *
 * @author Slayer
 */
public class Situation implements Cloneable {

    private Rule rule;
    private ItemInfo avanChain;
    private int pointPosition;

    public Situation(Rule rule, ItemInfo avanChain) {
        this.rule = (Rule) rule.clone();
        this.avanChain = (ItemInfo) avanChain.clone();
        this.pointPosition = 0;
    }

    public Situation(Rule rule, ItemInfo avanChain, int pointPosition) {
        this.rule = (Rule) rule.clone();
        this.avanChain = (ItemInfo) avanChain.clone();
        this.pointPosition = pointPosition;
    }

    public ItemInfo getAvanChain() {
        return avanChain;
    }

    public int getPointPosition() {
        return pointPosition;
    }

    /**
     * Gets alpha part of rule alpha part.
     *
     * @param rule Rule of the grammar
     * @return Item
     */
    public ItemList getAlpha() {
        ItemList list = new ItemList();
        ItemList expansion = rule.getTo();

        for (int index = 0; index < pointPosition && index < expansion.size(); ++index) {
            list.add(expansion.get(index));
        }

        return list;
    }

    public ItemInfo getB() {
        ItemList items = rule.getTo();

        if (pointPosition >= items.size()) {
            return EMPTY;
        } else {
            return items.get(pointPosition);
        }
    }

    public ItemList getBeta() {
        ItemList list = new ItemList();
        ItemList expansion = rule.getTo();

        for (int index = pointPosition + 1; index < expansion.size(); ++index) {
            list.add(expansion.get(index));
        }

        return list;
    }

    public boolean movePoint() {
        ItemList expansion = rule.getTo();
        // Calculate alpha, B and beta on movePoint
        if (pointPosition < expansion.size()) {
            ++pointPosition;

            return true;
        }

        return false;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Situation other = (Situation) obj;
        if (this.rule != other.rule && (this.rule == null || !this.rule.equals(other.rule))) {
            return false;
        }
        if (this.avanChain != other.avanChain && (this.avanChain == null || !this.avanChain.equals(other.avanChain))) {
            return false;
        }
        if (this.pointPosition != other.pointPosition) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 97 * hash + (this.rule != null ? this.rule.hashCode() : 0);
        hash = 97 * hash + (this.avanChain != null ? this.avanChain.hashCode() : 0);
        hash = 97 * hash + this.pointPosition;
        return hash;
    }

    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder();
        boolean addedPoint = false;

        builder.append("[").append(rule.getFrom()).append(" -> ");

        for (int index = 0; index < rule.getTo().size(); ++index) {
            if (pointPosition == index) {
                builder.append(".");
                addedPoint = true;
            }

            builder.append(rule.getTo().get(index));
        }

        if (!addedPoint) {
            builder.append(".");
        }

        builder.append(", ").append(avanChain.toString()).append("]");

        return builder.toString();
    }

    public Rule getRule() {
        return rule;
    }

    @Override
    public Object clone() {
        return new Situation((Rule) rule.clone(), (ItemInfo) avanChain.clone(), pointPosition);
    }
}
